[PATCH] dcerpc: use take instead of split_off(0)
authorPhilippe Antoine <pantoine@oisf.net>
Wed, 18 Feb 2026 14:00:08 +0000 (15:00 +0100)
committerAndreas Dolp <dev@andreas-dolp.de>
Thu, 23 Apr 2026 05:14:21 +0000 (07:14 +0200)
Ticket: 8304

Avoids quadratic complexity.
With split_off(0), the whole vec is copied, so if wa have other
calls supplying one byte at a time, we keep on copying increasing
data

Origin: upstream, https://github.com/OISF/suricata/commit/281f419c0481f7d24d8ce5482b962673a3938e9b.patch
Bug: https://redmine.openinfosecfoundation.org/issues/8304
Subject: Upstream fix for CVE-2026-31937

Gbp-Pq: Name CVE-2026-31937.patch

rust/src/dcerpc/dcerpc.rs

index 75fc151c6cb759477fe42335140fba8dbf9e85b7..22baf69f0d2ef1cc54935542ba4e70dafb7bf5ed 100644 (file)
@@ -467,18 +467,6 @@ impl DCERPCState {
         self.bytes_consumed = 0;
     }
 
-    pub fn extend_buffer(&mut self, buffer: &[u8], direction: Direction) {
-        match direction {
-            Direction::ToServer => {
-                self.buffer_ts.extend_from_slice(buffer);
-            }
-            Direction::ToClient => {
-                self.buffer_tc.extend_from_slice(buffer);
-            }
-        }
-        self.data_needed_for_dir = direction;
-    }
-
     pub fn reset_direction(&mut self, direction: Direction) {
         if direction == Direction::ToServer {
             self.data_needed_for_dir = Direction::ToClient;
@@ -965,24 +953,24 @@ impl DCERPCState {
             self.data_needed_for_dir = direction;
         }
 
-        let buffer = match direction {
+        let mut buffer = match direction {
             Direction::ToServer => {
                 if self.buffer_ts.len() + input_len > 1024 * 1024 {
                     SCLogDebug!("DCERPC TOSERVER stream: Buffer Overflow");
                     return AppLayerResult::err();
                 }
-                v = self.buffer_ts.split_off(0);
+                v = std::mem::take(&mut self.buffer_ts);
                 v.extend_from_slice(cur_i);
-                v.as_slice()
+                v
             }
             Direction::ToClient => {
                 if self.buffer_tc.len() + input_len > 1024 * 1024 {
                     SCLogDebug!("DCERPC TOCLIENT stream: Buffer Overflow");
                     return AppLayerResult::err();
                 }
-                v = self.buffer_tc.split_off(0);
+                v = std::mem::take(&mut self.buffer_tc);
                 v.extend_from_slice(cur_i);
-                v.as_slice()
+                v
             }
         };
 
@@ -996,9 +984,16 @@ impl DCERPCState {
         // Check if header data was complete. In case of EoF or incomplete data, wait for more
         // data else return error
         if self.bytes_consumed < DCERPC_HDR_LEN.into() && input_len > 0 {
-            parsed = self.process_header(buffer);
+            parsed = self.process_header(buffer.as_slice());
             if parsed == -1 {
-                self.extend_buffer(buffer, direction);
+                match direction {
+                    Direction::ToServer => {
+                        self.buffer_ts = std::mem::take(&mut buffer);
+                    }
+                    Direction::ToClient => {
+                        self.buffer_tc = std::mem::take(&mut buffer);
+                    }
+                }
                 return AppLayerResult::ok();
             }
             if parsed == -2 {
@@ -1011,7 +1006,14 @@ impl DCERPCState {
 
         if (buffer.len()) < fraglen as usize {
             SCLogDebug!("Possibly fragmented data, waiting for more..");
-            self.extend_buffer(buffer, direction);
+                match direction {
+                    Direction::ToServer => {
+                        self.buffer_ts = std::mem::take(&mut buffer);
+                    }
+                    Direction::ToClient => {
+                        self.buffer_tc = std::mem::take(&mut buffer);
+                    }
+                }
             return AppLayerResult::ok();
         } else {
             self.query_completed = true;